#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <semaphore.h>
#include <mutex>

template <class T>
class RingQueue
{
private:
    // 等待信号量
    void P(sem_t &s)
    {
        sem_wait(&s);
    }
    // 释放信号量
    void V(sem_t &s)
    {
        sem_post(&s);
    }

public:
    RingQueue(int max_cap)
        : _ringqueue(max_cap), _max_cap(max_cap), _c_step(0), _p_step(0)
    {
        //  1.信号量需要调用函数初始化：
        //  第二个参数pshared: 0表示线程间共享，非0表示进程间共享
        sem_init(&_data_sem, 0, 0);
        sem_init(&_space_sem, 0, max_cap);

        // 2.互斥锁需要初始化
        pthread_mutex_init(&_c_mutex, nullptr);
        pthread_mutex_init(&_p_mutex, nullptr);
    }
    // 入队列，生产者调用
    void Push(const T &in)
    {
        // 0.申请空间信号量
        P(_space_sem);

        // 1.生产者线程竞争申请锁：
        pthread_mutex_lock(&_p_mutex);

        // 2.向环形队列中进行生产
        _ringqueue[_p_step] = in;
        _p_step++;
        _p_step %= _max_cap;
        // 3.解锁
        pthread_mutex_unlock(&_p_mutex);

        // 4.释放数据资源
        V(_data_sem);
       
    }

    // 出队列
    void Pop(T *out)
    {
        // 0.申请数据信号量
        P(_data_sem);

        // 1.消费者线程竞争申请锁
        pthread_mutex_lock(&_c_mutex);

        // 2.从环形队列中得到数据
        *out = _ringqueue[_c_step];
        _c_step++;
        _c_step %= _max_cap;

        // 3.解锁
        pthread_mutex_unlock(&_c_mutex);

        // 4.释放空间资源
        V(_space_sem);

        
    }

    ~RingQueue()
    {
        sem_destroy(&_data_sem);
        sem_destroy(&_space_sem);

        pthread_mutex_destroy(&_c_mutex);
        pthread_mutex_destroy(&_p_mutex);

    }

private:
    // 1.队列和容量
    std::vector<T> _ringqueue;
    int _max_cap; // 最大容量

    // 2.消费者和生产者对应的位置，下标
    int _c_step;
    int _p_step;

    // 3.数据信号量和空间信号量
    sem_t _data_sem;
    sem_t _space_sem;

    // 4.消费者和生产者的互斥锁 
    pthread_mutex_t _c_mutex;
    pthread_mutex_t _p_mutex;
};